home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Franz PD / Franz PD Disk #067 (1990-04)(Amiga User Group Deutschland e.V.).zip / Franz PD Disk #067 (1990-04)(Amiga User Group Deutschland e.V.).adf / Source.zip / IO.p < prev    next >
Text File  |  1990-02-06  |  20KB  |  966 lines

  1. External;
  2.  
  3. {
  4.     IO.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid
  6.  
  7.     This module handles the IO of the compiler.  The actual
  8. compilation of the io statements is handled in stanprocs.p
  9. }
  10.  
  11. {$O-}
  12. {$I "Pascal.i"}
  13. {$I "Include/DOS.i" }
  14. {$I "Include/StringLib.i"}
  15. {$I "Include/Exec.i"}
  16.  
  17.  
  18. Function EndOfFile() : Boolean;
  19.  
  20. {
  21.     This just determines when the end of all input has occured.
  22. }
  23.  
  24. begin
  25.     EndOfFile := (InFile = nil) and (not CharBuffed);
  26. end;
  27.  
  28. Procedure AnnounceFile;
  29. begin
  30.     Write('\r\cK', LineNo:5, ' ', InFile^.Name, '\r');
  31. end;
  32.  
  33. Procedure WriteLineNo;
  34. begin
  35.     Write(Chr(13), LineNo:5);
  36. end;
  37.  
  38. Procedure CountLines;
  39.  
  40. { Does the bookkeeping for errors }
  41.  
  42. begin
  43.     if CurrentChar = Chr(10) then begin
  44.     LineNo := Succ(LineNo);
  45.     if Inform then
  46.         if (LineNo and 15) = 0 then
  47.         WriteLineNo;
  48.     end;
  49. end;
  50.  
  51. Procedure EndComment;
  52.     forward;    { It's in this module }
  53.  
  54. Procedure CloseInputFile;
  55.  
  56. { This closes the current input file and restores the saved stuff }
  57.  
  58. var
  59.     TempPtr : FileRecPtr;
  60. begin
  61.     if Inform then begin
  62.     WriteLineNo;
  63.     Writeln;
  64.     end;
  65.     Close(InFile^.PCQFile);
  66.     TempPtr := InFile^.Previous;
  67.     FreeString(InFile^.Name);
  68.     Dispose(InFile);
  69.     InFile := TempPtr;
  70.     if InFile <> nil then begin
  71.     LineNo := InFile^.SaveLine;
  72.     FNStart := InFile^.SaveStart;
  73.     CurrentChar := InFile^.SaveChar;
  74.     if Inform then
  75.         AnnounceFile;
  76.     EndComment;
  77.     end else
  78.     CurrentChar := Chr(0);
  79. end;
  80.  
  81. Procedure Abort;
  82.  
  83. {
  84.     This routine cuts out cleanly.  If you are debugging the
  85. compiler, this is a likely place to put post mortem dumps, like the
  86. one commented out.
  87. }
  88.  
  89. begin
  90.     While InFile <> nil do
  91.     CloseInputFile;
  92.     Close(OutFile);
  93.     Writeln('Compilation Aborted');
  94.     Exit(20);
  95. end;
  96.  
  97. Function OpenInputFile(name : String) : Boolean;
  98.  
  99. { This routine opens a new file record, and a new file.  It also
  100.   saves the state of the File-dependant variables, like LineNo. }
  101.  
  102. var
  103.     TempPtr : FileRecPtr;
  104.     OpenError : Integer;
  105. begin
  106.     New(TempPtr);
  107.     if not ReOpen(name, TempPtr^.PCQFile, 2048) then begin
  108.     Dispose(TempPtr);
  109.     OpenError := IOResult;
  110.     OpenInputFile := False;
  111.     end;
  112.     TempPtr^.Previous := InFile;
  113.     if InFile <> nil then begin
  114.     InFile^.SaveLine := LineNo;
  115.     InFile^.SaveStart := FNStart;
  116.     InFile^.SaveChar  := CurrentChar;
  117.     end;
  118.     LineNo := 1;
  119.     FNStart := 1;
  120.     TempPtr^.Name := AllocString(strlen(name));
  121.     strcpy(TempPtr^.Name, name);
  122.     InFile := TempPtr;
  123.     if EOF(InFile^.PCQFile) then
  124.     CloseInputFile
  125.     else
  126.     Read(Infile^.PCQFile, CurrentChar);
  127.     if Inform then
  128.     AnnounceFile;
  129.     OpenInputFile := True;
  130. end;
  131.  
  132. Function EQFix(x : integer): integer;
  133.  
  134. {
  135.     This helps implement a queue.  In this case it's for the
  136. error queue.
  137. }
  138.  
  139. begin
  140.     if x = -1 then
  141.     EQFix := EQSize
  142.     else
  143.     EQFix := x mod (Succ(EQSize));
  144. end;
  145.  
  146. Procedure Error(ptr : string);
  147.  
  148. {
  149.     This just writes out at most the previous 128 characters or
  150. two lines, then writes the error message passed to it.  If there
  151. are five errors, it aborts.
  152. }
  153.  
  154. var
  155.     index : integer;
  156.     newlines : integer;
  157. begin
  158.     index := EQEnd;
  159.     newlines := 0;
  160.     while (index <> EQStart) and (newlines < 2) do begin
  161.     index := EQFix(index - 1);
  162.     if ErrorQ[EQFix(index - 1)] = chr(10) then
  163.         newlines := newlines + 1;
  164.     end;
  165.  
  166.     if Inform then begin
  167.     write('\n\cK'); { newline, ClrEOL }
  168.     while index <> EQEnd do begin
  169.         if index = ErrorPtr then
  170.         write('\c0;33;40m');  { start highlight for ANSI }
  171.         write(ErrorQ[index]);
  172.         index := EQFix(index + 1);
  173.     end;
  174.     write('\c0;31;40m');  { end highlight }
  175.     writeln;
  176.     write('Line ', lineno, ' ');
  177.     if currfn <> nil then
  178.         write('(', CurrFn^.Name, ')');
  179.     writeln(': ', ptr, '\n');
  180.     end else
  181.     Writeln('Line ', LineNo, ' : ', ptr); { Quiet mode, no surprises }
  182.  
  183.     Inc(errorcount);
  184.     if errorcount > 4 then
  185.     Abort;
  186.     if CheckBreak() then
  187.     Abort;
  188.     if Inform then
  189.     AnnounceFile;
  190. end;
  191.  
  192. Procedure ReadChar;
  193.  
  194. { This is the main link between the lexical analysis stuff and the
  195.   IO stuff.  It sets up CurrentChar and keeps the line count. }
  196. var
  197.     IOError : Integer;
  198. begin
  199.     if CheckBreak() then
  200.     Abort;
  201.     if CharBuffed then begin
  202.     CurrentChar := BuffedChar;
  203.     CharBuffed := False;
  204.     return;
  205.     end;
  206.     if EOF(InFile^.PCQFile) then
  207.     CloseInputFile
  208.     else begin
  209.     Read(InFile^.PCQFile, CurrentChar);
  210.     IOError := IOResult;
  211.     CountLines;
  212.     end;
  213.     EQEnd := EQFix(Succ(EQEnd));
  214.     ErrorQ[EQEnd] := CurrentChar;
  215.     if EQStart = EQEnd then
  216.     EQStart := EQFix(Succ(EQStart));
  217. end;
  218.  
  219. Function NextChar() : Char;
  220. var
  221.     c : Char;
  222. begin
  223.     if not CharBuffed then begin
  224.     c := CurrentChar;
  225.     ReadChar;
  226.     BuffedChar := CurrentChar;
  227.     CurrentChar := c;
  228.     CharBuffed := True;
  229.     end;
  230.     NextChar := BuffedChar;
  231. end;
  232.  
  233. Procedure EndComment;
  234.  
  235. {
  236.     This just eats characters up to the end of a comment.  If
  237. you want nested comments, this is probably the place to do it.
  238. }
  239.  
  240. begin
  241.     while (Currentchar <> '}') and (not EndOfFile()) do
  242.     ReadChar;
  243.     if not EndOfFile() then
  244.     ReadChar;
  245. end;
  246.  
  247. Function GetLabel() : integer;
  248.  
  249. {
  250.     As in all compilers, this just returns a unique serial
  251. number.
  252. }
  253.  
  254. begin
  255.     Inc(NxtLab);
  256.     getlabel := nxtlab;
  257. end;
  258.  
  259. Procedure PrintLabel(lab : integer);
  260.  
  261. {
  262.     This routine prints a label based on a number from the
  263. above procedure.  The prefix for the label can be anything the
  264. assembler accepts - in this case I wanted it similar to the prefix
  265. of the run time library routines.  I didn't realize how ugly it
  266. would look.
  267. }
  268.  
  269. begin
  270.     write(OutFile, '_p%', lab);
  271. end;
  272.  
  273. Function JustFileName(S : String) : String;
  274.  
  275. { returns a string that is the file name part of a path.  It does
  276.   NOT allocate space. }
  277.  
  278. var
  279.     Ptr : String;
  280. begin
  281.     if S^ = Chr(0) then
  282.     JustFileName := S;
  283.     Ptr := String(Integer(S) + strlen(s) - 1);
  284.     while (Ptr^ <> ':') and (Ptr^ <> '/') do begin
  285.     if Ptr = S then
  286.         JustFileName := S;
  287.     Dec(Ptr);
  288.     end;
  289.     Inc(Ptr);
  290.     JustFileName := Ptr;
  291. end;
  292.  
  293. Procedure AddIncludeName(S : String);
  294.  
  295. { Adds the name of an include file to the list, so it won't be
  296.   included again. }
  297.  
  298. var
  299.     Ptr : IncludeRecPtr;
  300. begin
  301.     Ptr := IncludeRecPtr(AllocString(strlen(S) + 5));
  302.     if Ptr = nil then
  303.     Abort;
  304.     strcpy(Adr(Ptr^.Name), S);
  305.     Ptr^.Next := IncludeList;
  306.     IncludeList := Ptr;
  307. end;
  308.  
  309. Function AlreadyIncluded(S : String) : Boolean;
  310.  
  311. { Determines whether a file has been included already }
  312.  
  313. var
  314.     Ptr : IncludeRecPtr;
  315. begin
  316.     Ptr := IncludeList;
  317.     while Ptr <> nil do begin
  318.     if streq(Adr(Ptr^.Name), S) then
  319.         AlreadyIncluded := True;
  320.     Ptr := Ptr^.Next;
  321.     end;
  322.     AlreadyIncluded := False;
  323. end;
  324.  
  325. Procedure DoInclude;
  326.  
  327. {
  328.     The name says it all.  The mechanics of the include
  329. directive are all handled here.
  330. }
  331.  
  332. var
  333.     Ptr : String;
  334. begin
  335.     ReadChar;
  336.     While (CurrentChar <= ' ') and (not EndOfFile()) do
  337.     ReadChar;
  338.     if CurrentChar <> '"' then begin
  339.     Error("Missing Quote");
  340.     EndComment;
  341.     Return;
  342.     end;
  343.     ReadChar;
  344.     Ptr := SymText;
  345.     while CurrentChar <> '"' do begin
  346.     Ptr^ := CurrentChar;
  347.     Inc(Ptr);
  348.     if EndOfFile() then
  349.         Return;
  350.     ReadChar;
  351.     end;
  352.     Ptr^ := Chr(0); { mark then end of the file name }
  353.     ReadChar;        { read the end quote }
  354.     if not AlreadyIncluded(JustFileName(SymText)) then begin
  355.     if OpenInputFile(SymText) then
  356.         AddIncludeName(JustFileName(SymText))
  357.     else begin
  358.         Error("Could not open input file");
  359.         EndComment;
  360.     end;
  361.     end else
  362.     EndComment;
  363. end;
  364.  
  365. Procedure DoComment;
  366.  
  367. {
  368.     This routine implements compiler directives.
  369. }
  370.  
  371.     Procedure DoASM;
  372.     begin
  373.     ReadChar;
  374.     while CurrentChar <> '}' do begin
  375.         Write(OutFile, currentchar);
  376.         if EndOfFile() then begin
  377.         Error("File ended in a comment");
  378.         return;
  379.         end;
  380.         ReadChar;
  381.     end;
  382.     ReadChar;
  383.     Writeln(OutFile);
  384.     end;
  385.  
  386.     Procedure DoOnOff(var Flag : Boolean);
  387.     begin
  388.     ReadChar;
  389.     if CurrentChar = '+' then
  390.         Flag := True
  391.     else if CurrentChar = '-' then
  392.         Flag := False;
  393.     end;
  394.  
  395.     Procedure DoStorage;
  396.     var
  397.     KillChar : Boolean;
  398.     begin
  399.     ReadChar;
  400.     KillChar := True;
  401.     case CurrentChar of
  402.       'X' : StandardStorage := st_external;
  403.       'P' : StandardStorage := st_private;
  404.       'N' : StandardStorage := st_internal;
  405.     else begin
  406.         Error("Unknown storage class");
  407.         KillChar := False;
  408.          end;
  409.     end;
  410.     if KillChar then
  411.         ReadChar;
  412.     end;
  413.  
  414. begin
  415.     readchar;
  416.     if currentchar = '$' then begin
  417.     repeat
  418.         readchar; { either $ or , }
  419.         Case CurrentChar of
  420.           'I' : begin
  421.             DoInclude;
  422.             return;
  423.             end;
  424.           'A' : begin
  425.             DoASM;
  426.             return;
  427.             end;
  428.           'R' : DoOnOff(RangeCheck);
  429.           'O' : DoOnOff(IOCheck);
  430.           'S' : DoStorage;
  431.         else begin
  432.             Error("Unknown Directive");
  433.             EndComment;
  434.             return;
  435.          end;
  436.         end;
  437.         if (CurrentChar <> ',') or EndOfFile then begin
  438.         EndComment;
  439.         return;
  440.         end;
  441.     until false;
  442.     end else
  443.     EndComment;
  444. end;
  445.  
  446. Function Alpha(c : char): boolean;
  447.  
  448. {
  449.     This function answers the eternal question "is this
  450. character an alphabetic character?"  Note that _ is.
  451. }
  452.  
  453. begin
  454.     c := toupper(c);
  455.     Alpha := ((c >= 'A') and (c <= 'Z')) or (c = '_');
  456. end;
  457.  
  458. Function AlphaNumeric(c : char): boolean;
  459.  
  460. {
  461.     Is the character a letter or digit?
  462. }
  463.  
  464. begin
  465.     AlphaNumeric := Alpha(c) or isdigit(c);
  466. end;
  467.  
  468. Procedure Header;
  469.  
  470. {
  471.     This routine references all the run time library routines.
  472. One thing I like about A68k is that the only routines that will
  473. actually be referenced are those that are used in the code.  Maybe
  474. all assemblers do this, but I don't know.
  475. }
  476.  
  477. begin
  478.     writeln(OutFile, "* Pascal compiler intermediate assembly program.\n\n");
  479.     writeln(OutFile, "\tSECTION\tONE\n");
  480.     writeln(OutFile, "\tXREF\t_Input");
  481.     writeln(OutFile, "\tXREF\t_Output");
  482.     writeln(OutFile, "\tXREF\t_p%WriteInt");
  483.     writeln(OutFile, "\tXREF\t_p%WriteReal");
  484.     writeln(OutFile, "\tXREF\t_p%WriteChar");
  485.     writeln(OutFile, "\tXREF\t_p%WriteBool");
  486.     writeln(OutFile, "\tXREF\t_p%WriteCharray");
  487.     writeln(OutFile, "\tXREF\t_p%WriteString");
  488.     writeln(OutFile, "\tXREF\t_p%WriteLn");
  489.     writeln(OutFile, "\tXREF\t_p%ReadInt");
  490.     writeln(OutFile, "\tXREF\t_p%ReadReal");
  491.     writeln(OutFile, "\tXREF\t_p%ReadCharray");
  492.     writeln(OutFile, "\tXREF\t_p%ReadChar");
  493.     writeln(OutFile, "\tXREF\t_p%ReadString");
  494.     writeln(OutFile, "\tXREF\t_p%ReadLn");
  495.     writeln(OutFile, "\tXREF\t_p%ReadArb");
  496.     writeln(OutFile, '\tXREF\t_p%FilePtr');
  497.     writeln(OutFile, '\tXREF\t_p%Get');
  498.     writeln(OutFile, '\tXREF\t_p%Put');
  499.     writeln(OutFile, "\tXREF\t_p%dispose");
  500.     writeln(OutFile, "\tXREF\t_p%new");
  501.     writeln(OutFile, "\tXREF\t_p%Open");
  502.     writeln(OutFile, "\tXREF\t_p%WriteArb");
  503.     writeln(OutFile, "\tXREF\t_p%Close");
  504.     writeln(OutFile, "\tXREF\t_p%exit");
  505.     writeln(OutFile, "\tXREF\t_p%lmul");
  506.     writeln(OutFile, "\tXREF\t_p%ldiv");
  507.     writeln(OutFile, "\tXREF\t_p%lrem");
  508.     writeln(OutFile, "\tXREF\t_p%MathBase");
  509.     writeln(OutFile, '\tXREF\t_p%sin');
  510.     writeln(OutFile, '\tXREF\t_p%cos');
  511.     Writeln(OutFile, '\tXREF\t_p%CheckIO');
  512.     Writeln(OutFile, '\tXREF\t_p%CheckRange\n');
  513.     if mainmode then begin
  514.     writeln(OutFile, "\tXREF\t_p%initialize");
  515.     writeln(OutFile, "\tjsr\t_p%initialize");
  516.     writeln(OutFile, "\tjsr\t_MAIN");
  517.     writeln(OutFile, '\tmoveq.l\t#0,d0');
  518.     writeln(OutFile, "\tjsr\t_p%exit");
  519.     writeln(OutFile, "\trts");
  520.     end
  521. end;
  522.  
  523. Procedure Trailer;
  524.  
  525. {
  526.     This routine is the most important in the compiler
  527. }
  528.  
  529. begin
  530.     writeln(OutFile, "\tEND");
  531. end;
  532.  
  533. Procedure Blanks;
  534.  
  535. {
  536.     blanks() skips spaces, tabs and eoln's.  It handles
  537. comments if it comes across one.
  538. }
  539.  
  540. var
  541.     done : boolean;
  542. begin
  543.     while ((CurrentChar <= ' ') or (CurrentChar = '{')) and
  544.       (not EndOfFile()) do begin
  545.     if CurrentChar = '{' then
  546.         DoComment
  547.     else
  548.         ReadChar;
  549.     end;
  550. end;
  551.  
  552. Procedure DumpLitQ(k : Integer);
  553.  
  554. {
  555.     This procedure dumps the literal table at the end of the
  556. compilation.  Individual components are referenced as offsets to
  557. the literal label.
  558. }
  559.  
  560. var
  561.     j        : integer;
  562.     quotemode    : boolean;
  563. begin
  564.     while k < litptr do begin
  565.     write(OutFile, "\tdc.b\t");
  566.     j := 0;
  567.     quotemode := false;
  568.     while j < 40 do begin
  569.         if (ord(litq[k]) > 31) and (ord(litq[k]) <> 39) then begin
  570.         if quotemode then
  571.             write(OutFile, litq[k])
  572.         else begin
  573.             if j > 0 then
  574.             write(OutFile, ',');
  575.             write(OutFile, chr(39), litq[k]);
  576.             quotemode := true;
  577.         end;
  578.         end else begin
  579.         if quotemode then begin
  580.             write(OutFile, chr(39));
  581.             quotemode := false;
  582.         end;
  583.         if j > 0 then
  584.             write(OutFile, ',');
  585.         write(OutFile, ord(litq[k]));
  586.         if j > 32 then
  587.             j := 40
  588.         else
  589.             j := j + 3;
  590.         end;
  591.         j := j + 1;
  592.         k := k + 1;
  593.         if k >= litptr then
  594.         j := 40;
  595.     end;
  596.     if quotemode then
  597.         write(OutFile, chr(39));
  598.     writeln(OutFile);
  599.     end
  600. end;
  601.  
  602. Procedure DumpLits;
  603. begin
  604.     if LitPtr = 0 then
  605.     return;
  606.     writeln(OutFile, '\n\tSECTION\tLITS,DATA');
  607.     PrintLabel(LitLab);
  608.     DumpLitQ(0);
  609. end;
  610.  
  611. Procedure DumpIds;
  612.  
  613. {
  614.     This routine does whatever is appropriate with the various
  615. identifers.  If it's a global, it either references it or allocates
  616. space.  Similar stuff for the other ids.  When the modularity of
  617. PCQ is better defined, this routine will have to do more work.
  618. }
  619.  
  620. var
  621.     CB        : BlockPtr;
  622.     ID        : IDPtr;
  623.     TP        : TypePtr;
  624.     i        : Integer;
  625.     isodd    : boolean;
  626. begin
  627.     if mainmode then
  628.     writeln(OutFile, "\n\tSECTION\tTHREE,BSS\n");
  629.     isodd := false;
  630.     CB := CurrentBlock;
  631.     while CB <> nil do begin
  632.     for i := 0 to Hash_Size do begin
  633.         ID := CB^.Table[i];
  634.         while ID <> nil do begin
  635.         case ID^.Object of
  636.           global : case ID^.Storage of
  637.                 st_internal,
  638.                 st_private  : begin
  639.                         TP := ID^.VType;
  640.                         if isodd and (TP^.Size > 1) then begin
  641.                         Writeln(OutFile, "\tCNOP\t0,2");
  642.                         isodd := False;
  643.                         end;
  644.                         if ID^.Storage <> st_private then
  645.                         Writeln(OutFile,"\tXDEF\t_", ID^.Name);
  646.                         Write(OutFile, '_', ID^.Name);
  647.                         Writeln(OutFile, "\tds.b\t", TP^.Size);
  648.                         if odd(TP^.Size) then
  649.                         isodd := not isodd;
  650.                       end;
  651.                end;
  652.           proc,
  653.           func  : if ID^.Storage = st_forward then
  654.                 Writeln(ID^.Name, ' was never defined.');
  655.         end;
  656.         ID := ID^.Next;
  657.         end;
  658.     end;
  659.     CB := CB^.Previous;
  660.     end;
  661. end;
  662.  
  663. Procedure DumpRefs;
  664.  
  665. {
  666.     This routine makes all the external references necessary.
  667. }
  668.  
  669. var
  670.     CB        : BlockPtr;
  671.     ID        : IDPtr;
  672.     i        : Integer;
  673. begin
  674.     writeln(OutFile);
  675.     CB := CurrentBlock;
  676.     while CB <> nil do begin
  677.     for i := 0 to Hash_Size do begin
  678.         ID := CB^.Table[i];
  679.         while ID <> nil do begin
  680.         if ID^.Storage = st_external then
  681.             writeln(OutFile, "\tXREF\t_", ID^.Name);
  682.         ID := ID^.Next;
  683.         end;
  684.     end;
  685.     CB := CB^.Previous;
  686.     end
  687. end;
  688.  
  689. Procedure SearchReserved;
  690.  
  691. {
  692.     This just does a binary chop search of the list of reserved
  693. words.
  694. }
  695.  
  696. var
  697.     top,
  698.     middle,
  699.     bottom    : Symbols;
  700.     compare    : Short;
  701. begin
  702.     Bottom := And1;
  703.     Top := LastReserved;
  704.     while Bottom <= Top do begin
  705.     middle := Symbols((Short(bottom) + Short(top)) div 2);
  706.     Compare := stricmp(Reserved[Middle], SymText);
  707.     if Compare = 0 then begin
  708.         CurrSym := Middle;
  709.         Return;
  710.     end else if Compare < 0 then
  711.         Bottom := Succ(Middle)
  712.     else
  713.         Top := Pred(Middle);
  714.     end;
  715.     CurrSym := Ident1;
  716. end;
  717.  
  718. Procedure ReadWord;
  719.  
  720. {
  721.     This reads a Pascal identifier into symtext.
  722. }
  723.  
  724. var
  725.     ptr        : string;
  726. begin
  727.     ptr := symtext;
  728.     repeat
  729.     Ptr^ := CurrentChar;
  730.     Ptr := String(Integer(Ptr) + 1);
  731.     ReadChar;
  732.     until not AlphaNumeric(CurrentChar);
  733.     Ptr^ := chr(0);
  734.     SearchReserved;
  735. end;
  736.  
  737. Function DigVal(c : Char) : Integer;
  738. begin
  739.     DigVal := Ord(c) - Ord('0');
  740. end;
  741.  
  742. Procedure ReadNumber;
  743.  
  744. {
  745.     This routine reads a literal integer.  Note that _ can be used.
  746. }
  747.  
  748. var
  749.     Divider : Real;
  750. begin
  751.     SymLoc := 0;
  752.     While isdigit(CurrentChar) do begin
  753.     SymLoc := (SymLoc * 10) + DigVal(CurrentChar);
  754.     ReadChar;
  755.     if CurrentChar = '_' then
  756.         ReadChar;
  757.     end;
  758.     CurrSym := Numeral1;
  759.     if (CurrentChar = '.') and isdigit(NextChar()) then begin { It's real! }
  760.     ReadChar; { skip the . }
  761.     RealValue := Float(SymLoc);
  762.     Divider := 10.0;
  763.     while isdigit(CurrentChar) do begin
  764.         RealValue := RealValue + (Float(DigVal(CurrentChar)) / Divider);
  765.         Divider := Divider * 10.0;
  766.         ReadChar;
  767.     end;
  768.     CurrSym := RealNumeral1;
  769.     end;
  770. end;
  771.  
  772. Procedure ReadHex;
  773.  
  774. {
  775.     readhex() reads a hexadecimal number.
  776. }
  777.  
  778. var
  779.    rc : integer;
  780. begin
  781.     ReadChar;
  782.     symloc := 0;
  783.     rc := ord(toupper(currentchar));
  784.     while isdigit(currentchar) or
  785.       ((rc >= ord('A')) and (rc <= ord('F'))) do begin
  786.  
  787. {$A    move.l    _SymLoc,d0
  788.     asl.l    #4,d0
  789.     move.l    d0,_SymLoc    ; symloc := symloc * 16;
  790. }
  791.     if isdigit(currentchar) then
  792.         symloc := symloc + ord(currentchar) - ord('0')
  793.     else
  794.         symloc := symloc + rc - ord('A') + 10;
  795.     ReadChar;
  796.     rc := ord(toupper(currentchar));
  797.     end;
  798.     currsym := numeral1;
  799. end;
  800.  
  801. Procedure WriteHex(num : integer);
  802.  
  803. {
  804.     This writes full 32 bit hexadecimal numbers.
  805. }
  806.  
  807. var
  808.     numary  : array [1..8] of char;
  809.     pos     : integer;
  810.     ch      : char;
  811. begin
  812.     pos := 8;
  813.     while (num <> 0) and (pos > 0) do begin
  814. {$A    move.l    8(a5),d0
  815.     and.b    #15,d0
  816.     move.b    d0,-13(a5)    ; ch := num AND $0f;
  817. }
  818.     if ord(ch) < 10 then
  819.         numary[pos] := chr(ord(ch) + ord('0'))
  820.     else
  821.         numary[pos] := chr(ord(ch) + ord('A') - 10);
  822.     pos := pos - 1;
  823.  
  824. {$A    move.l    8(a5),d0
  825.     lsr.l    #4,d0
  826.     move.l    d0,8(a5)    ; num := num div 16;
  827. }
  828.     end;
  829.     if pos = 8 then begin
  830.     pos := 7;
  831.     numary[8] := '0';
  832.     end;
  833.     write(OutFile, '$');
  834.     for num := pos + 1 to 8 do
  835.     write(OutFile, numary[num]);
  836. end;
  837.  
  838. Procedure NextSymbol;
  839.  
  840. {
  841.     This is the workhorse lexical analysis routine.  It sets
  842. currsym to the appropriate symbol number, sets symtext equal to
  843. whatever identifier is read, and symloc to the value of a literal
  844. integer.
  845.     Soon this will be a big case statement.
  846. }
  847.  
  848. begin
  849.     ErrorPtr := EQEnd;
  850.     Blanks;
  851.     if EndOfFile then begin
  852.     CurrentChar := Chr(0);
  853.     CurrSym := EndText1; { I don't think this routine is ever hit }
  854.     Return;
  855.     end;
  856.     if Alpha(CurrentChar) then
  857.     readword
  858.     else if isdigit(currentchar) then
  859.     readnumber
  860.     else begin
  861.     case CurrentChar of
  862.       '[' : begin
  863.             CurrSym:= leftbrack1;
  864.             ReadChar;
  865.         end;
  866.       ']' : begin
  867.             CurrSym:= rightbrack1;
  868.             ReadChar;
  869.         end;
  870.       '(' : begin
  871.             CurrSym:= leftparent1;
  872.             ReadChar;
  873.         end;
  874.       ')' : begin
  875.             CurrSym:= rightparent1;
  876.             ReadChar;
  877.         end;
  878.       '+' : begin
  879.             CurrSym := plus1;
  880.             ReadChar;
  881.         end;
  882.       '-' : begin
  883.             CurrSym := minus1;
  884.             ReadChar;
  885.         end;
  886.       '*' : begin
  887.             CurrSym:= asterisk1;
  888.             ReadChar;
  889.         end;
  890.       '/' : begin
  891.             CurrSym := RealDiv1;
  892.             ReadChar;
  893.         end;
  894.       '<' : begin
  895.             ReadChar;
  896.             if CurrentChar = '=' then begin
  897.             CurrSym := notgreater1;
  898.             ReadChar;
  899.             end else if currentchar = '>' then begin
  900.             CurrSym := notequal1;
  901.             ReadChar;
  902.             end else
  903.             CurrSym:= less1;
  904.         end;
  905.       '=' : begin
  906.             CurrSym:= equal1;
  907.             ReadChar;
  908.         end;
  909.       '>' : begin
  910.             ReadChar;
  911.             if CurrentChar = '=' then begin
  912.             CurrSym:= notless1;
  913.             ReadChar;
  914.             end else
  915.             CurrSym:= greater1;
  916.         end;
  917.       ':' : begin
  918.             ReadChar;
  919.             if CurrentChar = '=' then begin
  920.             CurrSym:= Becomes1;
  921.             ReadChar;
  922.             end else
  923.             CurrSym:= colon1;
  924.         end;
  925.       ',' : begin
  926.             CurrSym:= comma1;
  927.             ReadChar;    
  928.         end;
  929.       '.' : begin
  930.             ReadChar;
  931.             if CurrentChar = '.' then begin
  932.             CurrSym:= DotDot1;
  933.             ReadChar;
  934.             end else
  935.             CurrSym:= period1;
  936.         end;
  937.       ';' : begin
  938.             CurrSym:= semicolon1;
  939.             ReadChar;
  940.         end;
  941.       '\'': begin
  942.             CurrSym:= apostrophe1;
  943.             ReadChar;
  944.         end;
  945.       '"' : begin
  946.             CurrSym:= quote1;
  947.             ReadChar;
  948.         end;
  949.       '^' : begin
  950.             CurrSym:= carat1;
  951.             ReadChar;
  952.         end;
  953.       '@' : begin
  954.             CurrSym := At1;
  955.             ReadChar;
  956.         end;
  957.       '$' : ReadHex;
  958.      '\0' : CurrSym := EndText1;
  959.     else begin
  960.         Error("Unknown symbol.");
  961.         ReadChar;
  962.          end;
  963.     end; { Case }
  964.     end { Else }
  965. end;
  966.